/**
 * MIT License
 * 
 * Copyright (c) 2017 CaiDongyu
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.tunnel.user.core;
  
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.axe.interface_.mvc.Listener;
import org.axe.util.HttpUtil;
import org.axe.util.MD5Util;

import com.tunnel.client.config.Config;
import com.tunnel.common.constant.Constant;
import com.tunnel.common.nio.EventLoopGroupManager;
import com.tunnel.common.tunnel.TunnelDataQueueManager;
import com.tunnel.common.util.LogUtil;
import com.tunnel.common.util.PropsUtil;
import com.tunnel.common.util.StringUtil;
import com.tunnel.user.common.SysConfig;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;  
/**
 * S->C通讯管道
 * 初始连接时候，负责客户端注册
 * 注册成功后，负责启动汇报管道
 * 全部启动完成后，开始接受请求
 */
public class TunnelClient extends com.tunnel.client.tunnel.TunnelClient implements Listener{
      
    //bootstrap配置好
    public void start(){
    	EventLoopGroupManager.add(0, group);
    	bootstrap = new Bootstrap();
    	bootstrap.group(group)
         .channel(NioSocketChannel.class)
//             .option(ChannelOption.TCP_NODELAY, true)
         .handler(new ChannelInitializer<SocketChannel>() {
             @Override
             public void initChannel(SocketChannel ch) throws Exception {
                 ChannelPipeline p = ch.pipeline();
                 //5秒内没有数据发送，就需要发送一个心跳包维持服务端的连接
                 //由于此管道，除了在连接之初会汇报注册信息，剩余时间都没有数据上传，因此会每5秒一次心跳
             	 //10秒钟心跳检测，客户端5秒发一次心跳，如果10秒没收到，断开连接
             	 p.addLast(new IdleStateHandler(10, 0, 0,TimeUnit.SECONDS));
                 //请求内容不超过10M
                 p.addLast(new DelimiterBasedFrameDecoder(1024*1024*10,Unpooled.copiedBuffer(Constant.TUNNEL_DATA_END_FLAG_BYTES)));
                 p.addLast(new TunnelClientHandler(TunnelClient.this));
             }
         });
    	connect();
    }

	@Override
	public int index() {
		return 0;
	}

	@Override
	public void init() throws Exception {
		//加载配置
		String username = SysConfig.username();
		String password = MD5Util.getMD5Code(SysConfig.password());
		
		//验证账号密码是否ok
		Map<String,String> params = new HashMap<>();
		params.put("email", username);
		params.put("password", password);
		try {
			String httpResult = HttpUtil.sendPost("https://www.tunnel.cool/tunnel/get_server_ip", params);
			if(httpResult.contains("SUCCESS")){
				String[] httpResultSplit = httpResult.split(Constant.SPLIT_FLAG);
				String serverIp = httpResultSplit[1];
				
				//先补充初始化参数
				Properties properties = SysConfig.getProperties();
				properties.put("tunnel_server_ip", serverIp);
				properties.put("tunnel_server_port", "6661");
				properties.put("tunnel_speed", "10K");//上限定为10kb吧
				properties.put("name", username);
				
				//HTTP 转发
				String hostAry = SysConfig.host();
				properties.put("host_ary", hostAry);
				if(StringUtil.isNotEmpty(hostAry)){
					//查看域名和地址的映射
					String[] hostArySplit = hostAry.trim().split(",");
					
					for(String host:hostArySplit){
						//检查域名配置
						if(host != null) host=host.trim();
						if(StringUtil.isEmpty(host)){
							LogUtil.error("客户端[域名列表]配置错误：host_ary=" + hostArySplit);
							System.exit(0);
						}
						
						//检查域名映射配置
						String mapper = PropsUtil.getString(properties, host);
						if(mapper != null) mapper = mapper.trim();
						if(StringUtil.isEmpty(mapper)){
							LogUtil.error("客户端[域名映射]配置错误："+host+"=" + mapper);
							System.exit(0);
						}
						String[] ipAndPortConfig = mapper.split(":");
						if(ipAndPortConfig.length < 2){
							LogUtil.error("客户端[域名映射]配置错误（提示 ip:端口）："+host+"=" + mapper);
							System.exit(0);
						}
						//补成tunnel-client初始化需要的参数
						properties.put("host_"+host, mapper);
					}
				}
				
				Config.init(properties);//初始化tunnel-client参数
				
				//启动消息队列，自带心跳
				TunnelDataQueueManager.startTunnelDataQueue("Tunnel-Client", true);
				this.start();//启动客户端
			}else{
				LogUtil.error(httpResult);
				System.exit(0);
			}
		} catch (Exception e) {
			LogUtil.error(e);
			LogUtil.error("网络异常");
			System.exit(0);
		}
	}
    
}